package com.da.auth.security.config;


import com.da.auth.security.filter.JwtTokenOncePerRequestFilter;
import com.da.auth.security.filter.RequestLoggingFilter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import static org.springframework.security.config.Customizer.withDefaults;

/**
 * @Author: hyacinth
 * @CreateTime: 2025-02-10
 * @Version: 1.0
 */
@Configuration
@RequiredArgsConstructor
@EnableWebSecurity // 开启SpringSecurity的自定义配置（在SpringBoot项目中可以省略）
@EnableMethodSecurity // 开启全局函数权限
@Slf4j
public class SecurityConfig {

    // 自定义的用于认证的过滤器，进行jwt的校验操作
    private final JwtTokenOncePerRequestFilter jwtTokenFilter;

    // 认证用户无权限访问资源的处理器
    private final UserAccessDeniedHandler userAccessDeniedHandler;

    // 客户端进行认证数据的提交时出现异常，或者是匿名用户访问受限资源的处理器
    private final AnonymousAuthenticationHandler anonymousAuthentication;

    // 用户认证校验失败处理器
    private final LoginFailureHandler loginFailureHandler;


    /**
     * 创建BCryptPasswordEncoder注入容器，用于密码加密
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * 登录时调用AuthenticationManager.authenticate执行一次校验
     */
    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
        return config. getAuthenticationManager();
    }

    /**
     * 配置安全过滤器链
     *
     * @param http HttpSecurity对象，用于配置安全策略
     * @return 配置好的SecurityFilterChain对象
     * @throws Exception 如果在配置过程中发生异常
     */
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {

        log.info("<==========进入了SecurityConfig.filterChain==========>");
        // 添加自定义异常处理类
        http.exceptionHandling(configurer -> {
            configurer.accessDeniedHandler(userAccessDeniedHandler) // 配置认证用户无权限访问资源的处理器
                    .authenticationEntryPoint(anonymousAuthentication); // 配置匿名用户未认证的处理器
        });
        // 配置关闭csrf机制
        http.csrf(AbstractHttpConfigurer::disable);
        // 用户认证校验失败处理器
        http.formLogin(conf -> conf.failureHandler(loginFailureHandler));
        // STATELESS（无状态）：表示应用程序是无状态的，不创建会话
        http.sessionManagement(conf -> conf.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
        // 配置放行路径
        http.addFilterBefore(new RequestLoggingFilter(), UsernamePasswordAuthenticationFilter.class)
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers("/dl/**", "/user/createUser").permitAll() // 放行登录接口路径
                        .requestMatchers("/dailyGoals/**", "/dailyGoalCategories/**").authenticated()
                        .requestMatchers("/permission/**", "/role/**", "/api/**").hasAuthority("admin")

                )
                .formLogin(withDefaults()) // 使用默认的表单登录
                .httpBasic(withDefaults()); // 使用默认的 HTTP 基本认证;
//        http.addFilterBefore(jwtTokenFilter, UsernamePasswordAuthenticationFilter.class);
        log.info("<===============离开了SecurityConfig.filterChain==========>");
        return http.build();
    }


}
